package com.wqnmdb.im.client;

import com.alibaba.fastjson.JSONObject;
import com.wqnmdb.im.domain.netty.protobuf.Authentication;
import com.wqnmdb.im.domain.netty.protobuf.Message;
import com.wqnmdb.im.domain.netty.protobuf.NettyModel;
import com.wqnmdb.im.utils.DateUtil;
import io.netty.channel.*;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;

import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * 客户端处理器
 **/
@ChannelHandler.Sharable
public class NettyClientHandler extends ChannelInboundHandlerAdapter {

    private static int i = 0;

    private static String sessionId = null;
    /**
     * 计算有多少客户端接入，第一个string为客户端ip
     */
    private static final ConcurrentHashMap<ChannelId, ChannelHandlerContext> CLIENT_MAP = new ConcurrentHashMap<>();


    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        CLIENT_MAP.put(ctx.channel().id(), ctx);
        NettyModel.ReqModel.Builder reqMsg = NettyModel.ReqModel.newBuilder();
        Authentication.Auth.Builder builder = Authentication.Auth.newBuilder();
        builder.setAccessKey("Wlu6qr22VII=");
        builder.setSecretKey("e2PP4fmSgUg=");
        builder.setAppName("xiangkan");
        reqMsg.setCmd(996);
        reqMsg.setTimestamp(DateUtil.getNowInt());
        reqMsg.setAuth(builder);
        ctx.channel().writeAndFlush(reqMsg.build());
    }

    /**
     * @param ctx
     * @author xiongchuan on 2019/4/28 16:10
     * @DESCRIPTION: 有服务端端终止连接服务器会触发此函数
     * @return: void
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        ctx.close();
        System.out.println("服务端终止了服务");
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("回复数据" + msg);
        NettyModel.RespModel respModel = (NettyModel.RespModel) msg;
        TimeUnit.SECONDS.sleep(5);

        if (respModel.getType() == 996 && respModel.getCode() == 5000){
            NettyModel.ReqModel.Builder reqModel = NettyModel.ReqModel.newBuilder();
            reqModel.setCmd(96);
            reqModel.setTimestamp(DateUtil.getNowInt());
            JSONObject jo = new JSONObject();
            jo.put("toUserId", 10001);
            reqModel.setExtras(jo.toJSONString());
            ctx.channel().writeAndFlush(reqModel.build());
        }

        if (respModel.getType() == 96 && respModel.getCode() == 5000){
            JSONObject extras = JSONObject.parseObject(respModel.getExtras());
            sessionId = extras.getString("sessionId");
            Message.MessageInfo.Builder msgInfo = Message.MessageInfo.newBuilder();
            msgInfo.setUuid("85743sdhjf489ks923urdA");
            msgInfo.setMsgData("测试发消息");
            msgInfo.setToUserId(10001);
            msgInfo.setFromUserId(10001);
            msgInfo.setSessionId(sessionId);
            msgInfo.setTimestamp(1605324445);
            msgInfo.setMsgType(1);
            NettyModel.ReqModel.Builder reqModel = NettyModel.ReqModel.newBuilder();
            reqModel.setMsgInfo(msgInfo);
            reqModel.setTimestamp(DateUtil.getNowInt());
            reqModel.setCmd(2);
            ctx.channel().writeAndFlush(reqModel.build());
        }

        if (respModel.getType() == 2 && respModel.getMsgInfo() != null){
            NettyModel.ReqModel.Builder reqModel = NettyModel.ReqModel.newBuilder();
            reqModel.setCmd(3);
            JSONObject jo = new JSONObject();
            jo.put("uuid", respModel.getMsgInfo().getUuid());
            jo.put("status", 2);
            jo.put("sessionId", respModel.getMsgInfo().getSessionId());
            reqModel.setExtras(jo.toJSONString());
            reqModel.setTimestamp(DateUtil.getNowInt());
            ctx.channel().writeAndFlush(reqModel.build());
        }
    }


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("服务端发生异常【" + cause.getMessage() + "】");
        cause.printStackTrace();
        ctx.close();
    }


    /**
     * @param msg       需要发送的消息内容
     * @param channelId 连接通道唯一id
     * @author xiongchuan on 2019/4/28 16:10
     * @DESCRIPTION: 客户端给服务端发送消息
     * @return: void
     */
    public void channelWrite(ChannelId channelId, String msg) {
        ChannelHandlerContext ctx = CLIENT_MAP.get(channelId);
        if (ctx == null) {
            System.out.println("通道【" + channelId + "】不存在");
            return;
        }
        //将客户端的信息直接返回写入ctx
        ctx.writeAndFlush(msg);
    }

    /**
     * 心跳请求处理，每4秒发送一次心跳请求;
     *
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object obj) throws Exception {
        if (obj instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) obj;
            if (IdleState.ALL_IDLE.equals(event.state())) {
                System.out.println("\r\n循环请求的时间：" + System.currentTimeMillis() + "，次数" + i++);

                // 如果写通道处于空闲状态就发送心跳命令
                Random random = new Random();
                int num = random.nextInt(10);
                try {
                    TimeUnit.SECONDS.sleep(num);
                    NettyModel.ReqModel.Builder reqMsg = NettyModel.ReqModel.newBuilder();
                    reqMsg.setCmd(1);
                    reqMsg.setTimestamp(DateUtil.getNowInt());
                    ctx.channel().writeAndFlush(reqMsg.build());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}